# LeetCode 32、最长有效括号

# 一、题目描述

给你一个只包含 '('')' 的字符串,找出最长有效(格式正确且连续)括号子串的长度。

示例 1:

输入:s = "(()"
输出:2
解释:最长有效括号子串是 "()"

示例 2:

输入:s = ")()())"
输出:4
解释:最长有效括号子串是 "()()"

示例 3:

输入:s = ""
输出:0

提示:

  • 0 <= s.length <= 3 * 10^4
  • s[i]'('')'

# 二、题目解析

# 三、参考代码

# 1、Java 代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// https://leetcode-cn.com/problems/longest-valid-parentheses/
class Solution {
    public int longestValidParentheses(String s) {

        // 利用栈来保留访问路径
        Stack<Integer> stack = new Stack<Integer>();

        // maxLength 记录最长有效(格式正确且连续)括号子串的长度
        int maxLength = 0;

        // 设置变量 start 表示合法括号序列的起始索引位置,指向一个左括号,初始值为 0
        int start = 0 ;

        // 1、访问每个字符,假设当前索引为 i,结合访问的元素和栈是否为空,有以下几种情况:
        for(int i = 0 ; i < s.length() ; i++){
            
            // 2、访问到左括号时,不管栈是否为空,都把它存储起来
            if( s.charAt(i) == '('){

                stack.add(i);

            // 3、访问到右括号时
            }else{

                // 4、如果当前栈为空,说明这个右括号在前面没有和它匹配的左括号,那么 start 需要发生改变,
                // 下一个访问的字符 i + 1 有可能是左括号,所以 start = i + 1
                if(stack.isEmpty()) {

                    start = i + 1;

                // 5、如果当前栈不为空
                }else{
                    
                    // 6、弹出栈顶元素后
                    stack.pop();

                    // 7、如果栈为空,
                    // 说明以当前右括号为右端点的合法括号序列的左端点为start,则更新长度 i - start + 1
                    if(stack.isEmpty()){

                        maxLength =  Math.max(maxLength,i - start + 1);

                    // 8、如果栈不为空,
                    // 找到了一组合法的括号序列,左括号是刚刚弹出的元素,索引位置可以用栈顶元素索引加 1 获取到,
                    // 那么这组合法括号序列的长度为 i - ( stack.peek() + 1 ) + 1
                    }else{

                        maxLength =  Math.max(maxLength,i - (stack.peek() + 1) + 1);

                    }
                }
            }
        }
        return maxLength;
    }
}

# **2、C++代码

// 登录 AlgoMooc 官网获取更多算法图解
// https://www.algomooc.com
// 作者:程序员吴师兄
// 代码有看不懂的地方一定要私聊咨询吴师兄呀
// https://leetcode-cn.com/problems/longest-valid-parentheses/
class Solution {
public:
    int longestValidParentheses(string s) {
        // 利用栈来保留访问路径
        stack<int> stk;

        // maxLength 记录最长有效(格式正确且连续)括号子串的长度
        int maxLength = 0;

        // 设置变量 start 表示合法括号序列的起始索引位置,指向一个左括号,初始值为 0
        int start = 0 ;

        // 1、访问每个字符,假设当前索引为 i,结合访问的元素和栈是否为空,有以下几种情况:
        for(int i = 0 ; i < s.length() ; i++){
            
            // 2、访问到左括号时,不管栈是否为空,都把它存储起来
            if( s[i] == '('){

                stk.push(i);

            // 3、访问到右括号时
            }else{

                // 4、如果当前栈为空,说明这个右括号在前面没有和它匹配的左括号,那么 start 需要发生改变,
                // 下一个访问的字符 i + 1 有可能是左括号,所以 start = i + 1
                if(stk.empty()) {

                    start = i + 1;

                // 5、如果当前栈不为空
                }else{
                    
                    // 6、弹出栈顶元素后
                    stk.pop();

                    // 7、如果栈为空,
                    // 说明以当前右括号为右端点的合法括号序列的左端点为start,则更新长度 i - start + 1
                    if(stk.empty()){

                        maxLength =  max(maxLength,i - start + 1);

                    // 8、如果栈不为空,
                    // 找到了一组合法的括号序列,左括号是刚刚弹出的元素,索引位置可以用栈顶元素索引加 1 获取到,
                    // 那么这组合法括号序列的长度为 i - ( stack.peek() + 1 ) + 1
                    }else{

                        maxLength =  max(maxLength,i - (stk.top() + 1) + 1);

                    }
                }
            }
        }
        return maxLength;
    }
};

# 3、Python 代码

# 登录 AlgoMooc 官网获取更多算法图解
# https://www.algomooc.com
# 作者:程序员吴师兄
# 代码有看不懂的地方一定要私聊咨询吴师兄呀
# https://leetcode-cn.com/problems/longest-valid-parentheses/
class Solution:
    def longestValidParentheses(self, s: str) -> int:

        # 利用栈来保留访问路径
        stack = []

        # maxLength 记录最长有效(格式正确且连续)括号子串的长度
        maxLength = 0

        # 设置变量 start 表示合法括号序列的起始索引位置,指向一个左括号,初始值为 0
        start = 0 

        # 1、访问每个字符,假设当前索引为 i,结合访问的元素和栈是否为空,有以下几种情况:
        for i in range(len(s)):
            
            # 2、访问到左括号时,不管栈是否为空,都把它存储起来
            if s[i] == '(' : 

                stack.append(i)

            # 3、访问到右括号时
            else:

                # 4、如果当前栈为空,说明这个右括号在前面没有和它匹配的左括号,那么 start 需要发生改变,
                # 下一个访问的字符 i + 1 有可能是左括号,所以 start = i + 1
                if not stack :

                    start = i + 1

                # 5、如果当前栈不为空
                else:
                    
                    # 6、弹出栈顶元素后
                    stack.pop()

                    # 7、如果栈为空,
                    # 说明以当前右括号为右端点的合法括号序列的左端点为start,则更新长度 i - start + 1
                    if not stack : 

                        maxLength =  max(maxLength,i - start + 1)

                    # 8、如果栈不为空,
                    # 找到了一组合法的括号序列,左括号是刚刚弹出的元素,索引位置可以用栈顶元素索引加 1 获取到,
                    # 那么这组合法括号序列的长度为 i - ( stack[-1] + 1 ) + 1
                    else:

                        maxLength =  max(maxLength,i - (stack[-1] + 1) + 1)

        return maxLength

# 四、复杂度分析

  • 时间复杂度: O(n),n 是给定字符串的长度。我们只需要遍历字符串一次即可。
  • 空间复杂度: O(n)。栈的大小在最坏情况下会达到 n,因此空间复杂度为 O(n)。